﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Wyse.Server.Logging;

namespace Wyse.Server.Base
{
    /// <summary>
    /// Base server - manages all listeners
    /// </summary>
    public class ServerBase
    {
        /// <summary>
        /// Adds a module to this server
        /// </summary>
        protected void AddModule(ServerModule module)
        {
            if (IsRunning)
                throw new InvalidOperationException();

            mModules.Add(module);
        }

        /// <summary>
        /// Adds a new listener to the server
        /// </summary>
        /// <param name="listener"></param>
        private void AddListener(Listener listener)
        {
            mListeners.Add(new ListenerThread(listener));

            Log.Print(LogLevel.Info, "Created listener {0} on {1}", listener.Name, listener.EndPoint);
        }

        /// <summary>
        /// Starts the server
        /// </summary>
        public virtual void Start()
        {
            InitModules();

            int listenerCount = InitListeners();

            if (listenerCount == 0)
            {
                Log.Print(LogLevel.Warning, "No listeners created - exiting");
                return;
            }
            else
                Log.Print(LogLevel.Info, "Starting {0} listeners", listenerCount);

            IsRunning = true;

            try
            {
                WaitHandle[] waitHandles = new WaitHandle[mListeners.Count];

                int i = 0;

                lock (mListeners)
                {
                    foreach (var l in mListeners)
                        waitHandles[i++] = l.Start();
                }

                WaitHandle.WaitAll(waitHandles);
            }
            finally
            {
                lock (mListeners)
                {
                    foreach (var l in mListeners)
                        l.Dispose();
                    mListeners.Clear();
                }

                IsRunning = false;
            }
        }

        /// <summary>
        /// Stops all listeners
        /// </summary>
        public virtual void Stop()
        {
            lock (mListeners)
            {
                foreach (var l in mListeners)
                    l.Stop();
            }
        }

        /// <summary>
        /// Gets a value indicating if the server is currently running (listening)
        /// </summary>
        public bool IsRunning
        {
            get;
            private set;
        }

        /// <summary>
        /// Initializes all listeners
        /// </summary>
        private int InitListeners()
        {
            foreach(var m in mModules)
            {
                foreach (var l in m.CreateListeners())
                    AddListener(l);
            }

            return mListeners.Count;
        }

        /// <summary>
        /// Initializes all modules
        /// </summary>
        private void InitModules()
        {
            foreach (var m in mModules)
            {
                Log.Print(LogLevel.Info, "Initializing module {0}", m.Name);

                m.Init();
            }
        }

        protected List<ServerModule> mModules = new List<ServerModule>();
        private List<ListenerThread> mListeners = new List<ListenerThread>();
    }
}
